package com.qust.enDecrpytion.encryptionAndDecryption.remote;

import com.alibaba.fastjson2.JSONObject;
import com.qust.agreement.Enums.InstructionEnum;
import com.qust.agreement.Message;
import com.qust.agreement.message.DecryptionMessage;
import com.qust.agreement.message.EncryptionMessage;
import com.qust.agreement.result.Result;
import com.qust.enDecrpytion.looPool.ChannelLooPool;
import com.qust.encryptionAndDecryption.IEnDecryption;
import com.qust.util.NettyUtils.MessageHandle;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Promise;
import lombok.extern.log4j.Log4j2;

import java.util.Map;
import java.util.concurrent.ExecutionException;
@Log4j2
public class RemoteEnDecryption implements IEnDecryption {

    private int code;
    private EventLoopGroup eventLoopGroup;
    private ChannelLooPool loopPool;
    private Promise<Message> promise;

    public RemoteEnDecryption(EventLoopGroup eventLoopGroup,int code, ChannelLooPool loopPool) {
        this.loopPool = loopPool;
        this.eventLoopGroup = eventLoopGroup;
        this.code = code;
    }

    @Override
    public String encryption(String value) {
        return send(value, InstructionEnum.encryption.getCode());
    }

    @Override
    public String decryption(String value) {
        return send(value, InstructionEnum.decryption.getCode());
    }

    private String send(String value, int instruction) {
        com.qust.enDecrpytion.looPool.LooPool.Node<Map<Channel, MessageHandle>> idleNode = loopPool.getIdleNode(eventLoopGroup);
        Map<Channel, MessageHandle> map = idleNode.getNode();
        Channel channel = map.keySet().iterator().next();
        MessageHandle messageInHandle = map.values().iterator().next();
        try {
            promise = new DefaultPromise<>(this.eventLoopGroup.next());
            messageInHandle.setResultPromise(promise);
            if (instruction == InstructionEnum.decryption.getCode()){
                channel.writeAndFlush(new DecryptionMessage(new Message.EnDecryptionContext(code,value))).sync();
            }else if (instruction == InstructionEnum.encryption.getCode()){
                channel.writeAndFlush(new EncryptionMessage(new Message.EnDecryptionContext(code,value))).sync();
            }
            Message message = promise.get();
            idleNode.close();

            JSONObject context = (JSONObject) message.getContext();
            return (String) context.to(Result.class).getData();
        } catch (ExecutionException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }


}
